#include "tcpServer.h"
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <iostream>
#include "macro.h"
#include <unistd.h>
#include "log.h"
//使用epoll进行监听，IO多路复用
//使用Reactor模式，一个线程负责监听，
//另外的线程池中的线程负责每个连接的收发消息，和消息处理
static sylar::Logger::ptr g_logger=DANIEL_LOG_NAME("system");
namespace daniel
{
    // ip不传入，默认使用IN_ADDRANY
    TcpServer::TcpServer(uint16_t port, const std::string &ip):m_ip(ip),m_port(port)
    {
        init(m_port, m_ip);
    }
    TcpServer::TcpServer(const ServerDefine &serverDefine)
    {
        m_ip=serverDefine.ip;
        m_port=serverDefine.port;
        init(m_port,m_ip);
    }

    TcpServer::~TcpServer()
    {
        //释放lfd的资源
        if (m_lfd != -1)
        {
            close(m_lfd);
        }
    }

    void TcpServer::init(uint16_t port, const std::string &ip)
    {
        m_lfd = socket(AF_INET, SOCK_STREAM, 0);
        if (m_lfd < 0)
        {
            throw("socket error!\n");
        }
        int32_t ret = 0;
        int32_t on = 1;
        ret = setsockopt(m_lfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        if (ret == -1)
        {
            ret = errno;
            throw("set reuse port failed!\n");
        }
        struct sockaddr_in sockAddr;
        sockAddr.sin_family = AF_INET;
        if (!ip.empty())
        {
            inet_pton(AF_INET, ip.c_str(), (void *)&sockAddr.sin_addr.s_addr);
        }
        else
        {
            sockAddr.sin_addr.s_addr = INADDR_ANY;
        }
        sockAddr.sin_port = htons(port);

        ret = bind(m_lfd, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
        if (ret < 0)
        {
            throw("bind error!\n");
        }
        ret = listen(m_lfd, 128);
        if (ret < 0)
        {
            throw("listen error!\n");
        }
    }
    //实现accept功能，使用epoll/poll/select实现均可
    //使用时，在一个线程中，循环启动acceptConnfd,互动TcpSoket对象，并不断处理;
    TcpSocket *TcpServer::acceptConnfd(int timeout)
    {
        struct timeval tv;
        tv.tv_sec = 0;
        tv.tv_usec = timeout * 1000;
        //创建监听的字符集合
        fd_set rfds;
        FD_ZERO(&rfds);
        FD_SET(m_lfd, &rfds);
        //监听m_lfd的读事件，如果有读事件发生，说明有客户端连接
        while (1)
        {
            int retval = select(m_lfd + 1, &rfds, nullptr, nullptr, &tv);
            if (retval > 0)
            {
                struct sockaddr_in clientAddr;
                uint32_t addrLen = sizeof(clientAddr);
                int32_t cfd = accept(m_lfd, (struct sockaddr *)&clientAddr, &addrLen);
                if (cfd > 0)
                {
                    char clientIP[128];
                    inet_ntop(AF_INET, (void *)&clientAddr.sin_addr.s_addr, clientIP, 128);
                    std::cout << "connect from IP:" << clientIP << std::endl;
                    //生成一个文件描述符，使用生成的文件描述符生成TcpSocket
                    return new TcpSocket(cfd);
                }
                else
                {
                    DANIEL_ASSERT2(false, "accept false!")
                }
            }
            else if (retval == 0)
            {
                //相当于短连接；
                // std::cout << "" << std::endl;
                DANIEL_LOG_DEBUG(g_logger)<<"连接超时,在规定时间内，无访问！";
                break;
            }
            else
            {
                //说明select被信号打断，重新监听
                if (errno == EINTR)
                    continue;
                else
                {
                    return nullptr;
                }
            }
        }
        return nullptr;
    }
    void TcpServer::disconnect()
    {
        if (m_lfd > 0)
        {
            close(m_lfd);
        }
        m_lfd = -1;
    }

    template <>
    class LexicalCast<ServerDefine, std::string>
    {
    public:
        std::string operator()(const ServerDefine &serverDef)
        {
            YAML::Node root;
            root["ip"] = serverDef.ip;
            root["port"] = serverDef.port;
            std::stringstream ss;
            ss << root;
            return ss.str();
        }
    };
    template <>
    class LexicalCast<std::string, ServerDefine>
    {
    public:
        ServerDefine operator()(const std::string &str)
        {
            ServerDefine serverDef;
            YAML::Node root = YAML::Load(str);
            serverDef.ip = root["ip"].as<std::string>();
            serverDef.port = root["port"].as<uint16_t>();
            return serverDef;
        }
    };
    //全局变量的初始化，早于main函数   向配置map中，调用了一个类型
    daniel::ConfigVar<ServerDefine>::ptr g_server = daniel::ConfigMsg::GetInstance()->lookUp("net", ServerDefine(), "server configs");
}